#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<eigen3/Eigen/Eigen>
#include<cstdlib>
#include<ctime>

using namespace cv;
using namespace Eigen;

class line_def
{
public:
    float a,b;
    int p1x,p1y,p2x,p2y;
    Vector2d way;      /*从起点到终点的向量*/
    int flag;
    line_def(float a1,float b1,float p1x1,float p1y1,float p2x1,float p2y1,int flag1);
    int dinside(float m,float n);
    float distance(float m,float n);
    ~line_def();
};

line_def::line_def(float a1,float b1,float p1x1,float p1y1,float p2x1,float p2y1,int flag1)    /*初始化，a、b是线段系数，p是起点终点，flag表示第几条*/
{
    a = a1;
    b = b1;
    p1x = p1x1;
    p1y = p1y1;
    p2x = p2x1;
    p2y = p2y1;
    way = Vector2d(p2x - p1x,p2y - p1y);
    flag = flag1;
}

int line_def::dinside(float m,float n)    /*输入点判断点在线段哪侧的函数*/
{
    Vector3d l(m - p1x,n - p1y,0);
    Vector3d s(0,0,1);
    Vector3d p(p2x - p1x,p2y - p1y,0);
    if (p.cross(l).dot(s) >= 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

float line_def::distance(float m,float n)    /*线段类的函数，传入点，判断点到线段的距离*/
{
    Vector2d o1,o2;     /*线段左右两点指向目标点的向量*/
    o1 = Vector2d(m - p1x ,n - p1y);
    o2 = Vector2d(m - p2x ,n - p2y);

    float chuizhi;      /*计算与直线的垂直距离*/
    chuizhi = (abs(a*m - n + b)/sqrtf32(a*a + 1));
    
    float result;

    if (flag == 1)      /*分第几条线的情况*/
    {
        if (way.dot(o1)<0 and way.dot(o2)<0)    /*根据点的位置选择合适的距离，以下同*/
        {
            result = chuizhi;
        }
        else if (way.dot(o1)>0 and way.dot(o2)>0)
        {
            result = o2.norm();
        }
        else
        {
            result = chuizhi;
        }
    }
    else if (flag == 2)
    {
        if (way.dot(o1)<0 and way.dot(o2)<0)
        {
            result = o1.norm();
        }
        else if (way.dot(o1)>0 and way.dot(o2)>0)
        {
            result = o2.norm();
        }
        else
        {
            result = chuizhi;
        }
    }
    else
    {
        if (way.dot(o1)<0 and way.dot(o2)<0)
        {
            result = o1.norm();
        }
        else if (way.dot(o1)>0 and way.dot(o2)>0)
        {
            result = chuizhi;
        }
        else
        {
            result = chuizhi;
        } 
    }

    return result;
}

line_def::~line_def()
{
}

float produce_point(float a[7][2])    /*随机生成线的端点*/
{
    srand((int)time(0));              /*增加随机性*/
    float q[7][2];                    
    for (int i = 0; i < 4; i++)
    {
        q[i][0] = rand()%598+1;       /*保证不靠边*/
        q[i][1] = rand()%398+1;
    }

    Vector2d v[3];                   /*计算向量用于判断角度并生成符合规则的点*/
    for (int i = 0; i < 3; i++)
    {
        v[i] = Vector2d(q[i+1][0]-q[i][0],q[i+1][1]-q[i][1]);
    }

    int decide1 = 1,decide2 = 1;    /*1判断钝锐角，2判断相交*/
    float j[3][2];
    float dx,dy;
    while (decide1 or decide2)
    {
        q[3][0] = rand()%598+1;
        q[3][1] = rand()%398+1;
        v[2] = Vector2d(q[3][0]-q[2][0],q[3][1]-q[2][1]);

        decide1 = 1;
        decide2 = 1;

        for (int i = 0; i < 3; i++)       /*计算各线段的系数*/
        {
            j[i][0] = (q[i+1][1] - q[i][1])/(q[i+1][0] - q[i][0]);
        }
        for (int i = 0; i < 3; i++)
        {
            j[i][1] = q[i+1][1] - q[i+1][0] * j[i][0];
        }

        dx = (j[2][1]-j[0][1])/(j[0][0]-j[2][0]);
        dy = dx*j[0][0] + j[0][1];

        Vector2d ori1(dx - q[1][0],dy - q[1][1]);       /*中间线段的两点到交点的向量*/
        Vector2d ori2(dx - q[2][0],dy - q[2][1]);

        if (dx>=0 and dx<600 and dy>=0 and dy<400 and ori1.dot(v[0])<0 and ori2.dot(v[2])>0)          /*判断相交，线段表达式求交点，同时保证不在图内*/
        {
            decide2 = 1;
        }
        else
        {
            decide2 = 0;
        }
        
        if (v[1].dot(v[0])*v[2].dot(v[1]) < 0)    /*一个钝角一个锐角*/
        {
            decide1 = 0;
        }
        else
        {
            decide1 = 1;
        }
    }

    for (int i = 4; i < 7; i++)    /*保留线的系数*/
    {
        q[i][0] = j[i-4][0];
        q[i][1] = j[i-4][1];
    }

    for (int i = 0; i < 7; i++)    /*传参*/
    {
        for (int l = 0; l < 2; l++)
        {
            a[i][l] = q[i][l];
        }
    }
    
    return q[7][2];
}

float min(float m1,float m2,float m3)    //求最小
{
    float re;
    re = m1;
    if (m2<re)
    {
        re = m2;
    }
    if (m3<re)
    {
        re = m3;
    }
    return re;
}

int main()
{
    float point[7][2];
    produce_point(point);    /*调用生成点的函数*/

    line_def line1(point[4][0],point[4][1],point[0][0],point[0][1],point[1][0],point[1][1],1);    /*初始化三条线段*/
    line_def line2(point[5][0],point[5][1],point[1][0],point[1][1],point[2][0],point[2][1],2);
    line_def line3(point[6][0],point[6][1],point[2][0],point[2][1],point[3][0],point[3][1],3);
    
    Mat Image_ori = Mat::zeros(400 ,600 ,CV_8UC3);         /*生成图像*/

    float guiyi = 0;
    float d1,d2,d3;
    for (int i = 0; i < 400; i++)     /*取得最大距离用于归一化*/
    {
        for (int e = 0; e < 600; e++)
        { 
            d1 = line1.distance(float(e),float(i));
            d2 = line2.distance(float(e),float(i));
            d3 = line3.distance(float(e),float(i));
            if (d1 >= guiyi)
            {
                guiyi = d1; 
            }
            if (d2 >= guiyi)
            {
                guiyi = d2; 
            }
            if (d3 >= guiyi)
            {
                guiyi = d3; 
            }
        }
    }

    int color1,color2;      /*color1设置锐角夹的部分，color2用于增加和排除相应部分*/
    int fang1,fang2;
    Vector3d way1(line1.p2x-line1.p1x,line1.p2y-line1.p1y,0);    /*建立三条线段的三维向量用于叉积*/
    Vector3d way2(line2.p2x-line2.p1x,line2.p2y-line2.p1y,0);
    Vector3d way3(line3.p2x-line3.p1x,line3.p2y-line3.p1y,0);
    Vector3d wayo(0,0,1);
    
    if (way1.cross(way2).dot(wayo)>0)      /*判断线段1在2的左右，左为1*/
    {
        fang1 = 1;
    }
    else
    {
        fang1 = 0;
    }
    if (way2.cross(way3).dot(wayo)>0)     /*判断线段3在2的左右，左为1*/
    {
        fang2 = 1;
    }
    else
    {
        fang2 = 0;
    }
    
    for (int e = 0; e < 600; e++)
    {
        for (int i = 0; i < 400 ; i++)
        {
            if (line1.way.dot(line2.way)<0)     /*如果1，2夹锐角，这部分用于设置锐角夹的部分为红色*/
            {
                if (fang1==1)    /*1在2的左边*/
                {
                    if (line1.dinside(float(e),float(i))==1 and line2.dinside(float(e),float(i))==1)
                    {
                        color1 = 1;
                    }
                    else
                    {
                        color1 = 0;   
                    }
                }
                else
                {
                    if (line1.dinside(float(e),float(i))==0 and line2.dinside(float(e),float(i))==0)
                    {
                        color1 = 1;
                    }
                    else
                    {
                        color1 = 0;
                    }
                }
            }
            else
            {
                if (fang2==1)    /*2在3的左边*/
                {
                    if (line2.dinside(float(e),float(i))==1 and line3.dinside(float(e),float(i))==1)
                    {
                        color1 = 1;
                    }
                    else
                    {
                        color1 = 0;
                    }
                }
                else
                {
                    if (line3.dinside(float(e),float(i))==0 and line2.dinside(float(e),float(i))==0)
                    {
                        color1 = 1;
                    }
                    else
                    {
                        color1 = 0;
                    }
                }
            }
            if (line1.way.dot(line2.way)<0)      /*这部分用于根据钝角排除多余或增加缺少的部分*/
            {
                if (fang1==1)    /*1在2的左边*/
                {
                    color2 = 0;
                    if (fang2==1)      /*2在3的左边*/
                    {
                        if (line3.dinside(float(e),float(i))==0)    /*剔除*/
                        {
                            color2 = -1;
                        }
                    }
                    else
                    {
                        if (line3.dinside(float(e),float(i))==1 and line2.dinside(float(e),float(i))==0)    /*增加*/
                        {
                            color2 = 1;
                        }
                    }
                }
                else
                {
                    color2 = 0;
                    if (fang2==1)
                    {
                        if (line3.dinside(float(e),float(i))==0 and line2.dinside(float(e),float(i))==1)
                        {
                            color2 = 1;
                        }
                    }
                    else
                    {
                        if (line3.dinside(float(e),float(i))==1)
                        {
                            color2 = -1;
                        }
                    }
                }
            }
            else
            {
                if (fang2==1)
                {
                    color2 = 0;
                    if (fang1==1)
                    {
                        if (line1.dinside(float(e),float(i))==0)
                        {
                            color2 = -1;
                        }
                    }
                    else
                    {
                        if (line1.dinside(float(e),float(i))==1 and line2.dinside(float(e),float(i))==0)
                        {
                            color2 = 1;
                        }
                    }
                }
                else
                {
                    color2 = 0;
                    if (fang1==1)
                    {
                        if (line1.dinside(float(e),float(i))==0 and line2.dinside(float(e),float(i))==1)
                        {
                            color2 = 1;
                        }
                    }
                    else
                    {
                        if (line1.dinside(float(e),float(i))==1)
                        {
                            color2 = -1;
                        }
                    }
                }
            }
            if ((color2+color1)>0.5)      /*剔除时color2设置为-1，增加设为1，而夹锐角时color1设为1，不夹为0，所以要剔1+（-1）=0，要加0+1=1，用0.5就可以区分*/
            {
                Image_ori.at<Vec3b>(i,e)[0] = 255;  
                Image_ori.at<Vec3b>(i,e)[1] = int(255*(1-min(line1.distance(float(e),float(i))/guiyi,line2.distance(float(e),float(i))/guiyi,line3.distance(float(e),float(i))/guiyi)));  
                Image_ori.at<Vec3b>(i,e)[2] = 255;
            }
            else
            {
                Image_ori.at<Vec3b>(i,e)[0] = 255;  
                Image_ori.at<Vec3b>(i,e)[1] = 255;  
                Image_ori.at<Vec3b>(i,e)[2] = int(255*(1-min(line1.distance(float(e),float(i))/guiyi,line2.distance(float(e),float(i))/guiyi,line3.distance(float(e),float(i))/guiyi)));
            }
        }
    }

    IplImage Image = IplImage(Image_ori);      /*转化用于显示*/
    CvArr* Image_fi= (CvArr*)&Image;

    for (int i = 0; i < 3; i++)       /*划线*/
    {
        cvLine(Image_fi, cvPoint(point[i][0],point[i][1]), cvPoint(point[i+1][0],point[i+1][1]), cvScalar(0,0,0 ), 2);
    }
	
    cvNamedWindow("Image",1);
	cvShowImage("Image",Image_fi);    /*展示图像*/
 
	cvWaitKey(0);

	cvDestroyWindow("Image");        /*释放窗口和图像的内存*/
    
    return 0;
}